#include "helper/sqlite/shortcut/Query.h"

#include "helper/sqlite/IDB.h"
#include "helper/sqlite/Statement.h"
#include "helper/sqlite/QueryResult.h"

#include <iostream>

namespace helper {
namespace sqlite {
namespace shortcut {

Query::Query(IDB & db) 
: DBWrapper(db)
{
}
Query::~Query() {
}

std::error_code Query::query(const std::string & sql, const fetch_type & ffetch, const fbind_type &  fbind ) const{
  std::error_code ec;
  auto && stmt = db().createStatement(sql, ec);
  if(!ec && stmt){
    if(fbind){
      ec = stmt->prepareInput(fbind);
      if(ec){
        return ec; 
      }
    }   

    if(ffetch){
      auto && r = stmt->query();
      return r ? ffetch(r) : r.errorCode();
    }   
    return std::make_error_code(std::errc::invalid_argument);
  }
  return ec;
}

std::error_code Query::query(const std::string & sql, const fvisit_row_type & fvisit_row, const fbind_type & fbind) const{
  auto && fetch = [&fvisit_row](auto & r){
    for(int row = 0; r ; r.next(), ++row){
      if(auto && ec = fvisit_row(row, r); ec){
        return ec;
      }
    }
    return std::error_code();
  };
  return query(sql, fetch, fbind);
}

std::error_code Query::query(const std::string & sql, const fvisit_value_type & fvisit_value, const fbind_type & fbind) const{
  auto && fetch = [&fvisit_value](auto & r){
    for(int row = 0; r ; r.next(), ++row){
      int cc = r.columnCount();
      for(int col = 0; col < cc; ++col){
        if(auto && ec = fvisit_value(row, col, r.values(col), r); ec){
          return ec;
        }
      }//for col
    }//for row
    return std::error_code();
  };
  return query(sql, fetch, fbind);
}

}//namespace shortcut
}//namespace sqlite
}//namespace helper
